package com.qlm.service.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.aop.Before;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.qlm.common.Define;
import com.qlm.service.IQrcodeAddService;
import com.qlm.tools.Common;
import com.qlm.tools.DESUtil;
import com.qlm.tools.DateUtils;
import com.qlm.tools.NumUtil;
import com.qlm.tools.StringUtils;
import com.qlm.tools.ZipCompressor;
import com.qlm.util.zxing.QrcodeConfig;
import com.qlm.util.zxing.QrcodeFactory;

public class QrcodeAddServiceImpl implements IQrcodeAddService {

	protected final static Logger logger = LoggerFactory
			.getLogger(QrcodeAddServiceImpl.class);
	private static Map<String, Integer> map = new HashMap<String, Integer>();

	private static final int length = 4;
	private static final int max = 1000000000;
	private static final int min = 100000000;
	/**
	 * 在数据库中生成二维码编号，并将二维码链接写入TXT文件，并将本次产码文件生成ZIP包
	 */
	@Override
	@Before(Tx.class)
	public String getZipFilePath(String url, Integer num,
			String filePath, Integer addNum, String id,String code,String money) {
		code=code.toLowerCase();
		logger.info("method getZipFilePath url=" + url);
		logger.info("method getZipFilePath code=" + code);
		logger.info("method getZipFilePath id=" + id);
		logger.info("method getZipFilePath filePath=" + filePath);
		logger.info("method getZipFilePath num=" + num);
		logger.info("method getZipFilePath addNum=" + addNum);
		// 判断传入参数是否正确
		if (!Common.isEmptyString(url)) {
			return "网络连接错误";
		}
		if (!Common.isEmptyString(id)) {
			return "网络连接错误";
		}
		if (!Common.isEmptyString(filePath)) {
			return "网络连接错误";
		}
		if (Common.isNullOrEmpty(addNum)) {
			return "网络连接错误";
		}
		if (Common.isNullOrEmpty(num)) {
			return "网络连接错误";
		}
		if (num > Define.ADD_QRCODE_MAX) {
			return "产码数量超过500W";
		}
		if (num < Define.ADD_QRCODE_MIN) {
			return "产码数量小于1";
		}

		String dbname = PropKit.use("config.properties").get("dbname");
		if(!Common.isEmptyString(dbname)){
			return "网络连接错误";
		}
		
		String sourceFilePath = null;// TXT文件路径
		String tablename = "t_qrcode_"+code;// 二维码表名
		String hbrecordtable = "t_qrcode_hbrecord_"+code;// 红包表名
		String scantable = "t_qrcode_scan_"+code;// 二维码表名
		String createTime = DateUtils.getStringFullDate();// 产码时间
		
		String sql = "select count(*) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='"+dbname+"' and TABLE_NAME= ? ";
		String qrcodeSql = "create table "+tablename+" (id int(11) NOT NULL AUTO_INCREMENT,key_ char(4) NOT NULL ,desc_ varchar(14) DEFAULT NULL,PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
		String scanSql = "create table "+scantable+" (qrcode_id int(9) NOT NULL DEFAULT '0' COMMENT '二维码id',openid varchar(255) DEFAULT NULL COMMENT '用户openid',"
				+ "scan_time datetime DEFAULT NULL COMMENT '扫码时间',scan_count int(11) DEFAULT NULL COMMENT '扫码个数',"
				+ "longitude varchar(20) DEFAULT NULL COMMENT '经度',latitude varchar(20) DEFAULT NULL COMMENT '纬度',"
				+ "site varchar(255) DEFAULT NULL COMMENT '位置', PRIMARY KEY (qrcode_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='扫码记录表' ";
		String hbrecordSql = "create table "+hbrecordtable+" (qrcode_id int(11) NOT NULL COMMENT '二维码id',openid varchar(255) DEFAULT NULL COMMENT '用户openid',"
				+ "money int(11) DEFAULT NULL COMMENT '红包金额，单位：分',send_time datetime DEFAULT NULL COMMENT '发送时间',"
				+ "send_state int(1) DEFAULT NULL COMMENT '发送状态', PRIMARY KEY (qrcode_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='红包记录表' ";
		if( Db.queryLong(sql,tablename) <= 0){
			Db.update(qrcodeSql);
		}
		if( Db.queryLong(sql,hbrecordtable) <= 0){
			Db.update(hbrecordSql);
		}
		if( Db.queryLong(sql,scantable) <= 0){
			Db.update(scanSql);
		}		
		
		
		
		String idSql = "select IFNULL(max(id),0) from "+tablename;
		long maxId = Db.queryLong(idSql);
		int insertCount = 0;// 已生成二维码数量
		put(map, id, insertCount);

		//加密字符串
		String status = StringUtils.getRandomStr(length);
		String desc = null;
		StringBuilder sb = new StringBuilder("insert into " + tablename
				+ " (key_,desc_) values ");
		for (int k = 0; k < num-1; k++) {// 拼接sql
			status = StringUtils.getRandomStr(length);
//			desc = NumUtil.getRandomNum(max, min);
			desc = StringUtils.getRandomNUmber()+getStr(k+1);
			sb.append("('").append(status).append("',").append("'").append(desc).append("'),");
			insertCount = k + 1;
			put(map, id, insertCount);
		}
		status = StringUtils.getRandomStr(length);
//		desc = NumUtil.getRandomNum(max, min);
		desc = StringUtils.getRandomNUmber()+getStr(num);
		sb.append("('").append(status).append("',").append("'").append(desc).append("')");
		Db.update(sb.toString());
		insertCount = num;
		put(map, id, insertCount);
		sb = null;
		
		//插入产码记录
		com.qlm.entity.Record r = new com.qlm.entity.Record();
		r.set("month_batch", code).set("create_time", createTime).set("id_begin", maxId+1)
		.set("id_end", maxId+num).set("valid", 0).set("number", num);
		if(Common.isEmptyString(money) && StringUtils.isNumeric(money)){
			BigDecimal m = new BigDecimal(money).multiply(new BigDecimal(100));
			r.set("money", m.intValue());
		}else{
			r.set("money", 0);
		}
		r.save();
		
		String summarySql = "update summary set total_qrcode_num = (select (a.total_qrcode_num+"+num+") from "
				+ "(select total_qrcode_num from summary ORDER BY create_time DESC limit 1) a)";
		Db.use("tongji").update(summarySql);
		
		//生成TXT文件
		sourceFilePath = getTxtPath(num, filePath, maxId, code ,tablename,
				addNum, createTime, url );
		
		map.remove(id);
		return getFilePath(filePath, sourceFilePath);
	}

	private String getStr(Integer num) {
		StringBuilder str = new StringBuilder();
		str.insert(0,num);
		if(str.length()<6){
			while(str.length()<6){
				str.insert(0,0);
			}				
			return str.reverse().toString();
		}else{
			String s = str.substring(str.length()-6, str.length());
			StringBuilder sb = new StringBuilder(s).reverse();
			return sb.toString();
		}
	}

	public String getFilePath(String filePath, String sourceFilePath) {
		if (sourceFilePath != null) {// 打包文件

			String fileName = "";
			File sourceFile = new File(sourceFilePath);
			if (sourceFile.exists()) {
				filePath = sourceFile.getParentFile().getAbsolutePath();
				fileName = sourceFile.getParentFile().getName();
			}
			ZipCompressor zc = new ZipCompressor(filePath+".zip");
			zc.compressExe(filePath);
			// 下载时候使用，@后面的为下载的文件名称，前面的为服务器文件路径
			String pathName = filePath + ".zip" + "@" + fileName;
			return pathName;
		}
		return "产码失败";
	}

	/**
	 * 将二维码链接写入TXT文件中，返回文件地址
	 */
	private String getTxtPath(int count, String filePath, long maxId,String code,
			String tablename, Integer addNum, String createTime, String url ) {

		// 加密
		DESUtil des = new DESUtil("qianlima");
		// 查询新插入二维码集合
		String sql1 = "select id,key_,desc_ from " + tablename + " where id > " + maxId;
		List<Record> idList = Db.find(sql1);
		if (idList.size() > 0) {// 集合不为空，生成txt文件

			// 文件路径为“://”+厂商名称+“//”+文件名称为产品名称_当前日期+"//"+生成数量.txt
			filePath = filePath + File.separator + "wzz_"+code+"_"+ createTime
					+ File.separator;
			filePath = filePath + code.toUpperCase()+(maxId + 1) + "_" +code.toUpperCase()+ (maxId + count) + ".txt";
			String s1 = new String();// 内容更新
			try {
				File f = new File(filePath);
				if (!f.getParentFile().exists()) {
					f.getParentFile().mkdirs();// 不存在则创建文件夹
				}
				if (!f.exists()) {
					f.createNewFile();
				}
				BufferedWriter output = new BufferedWriter(new FileWriter(f,
						true));
				for (int j = 0; j < count; j++) {
					// ticket的参数=产码批次(明文2位)+概率批次(明文1位)+二维码id(加密)
					// eg:1+02+sfdhasfhsdfjo, 1+12+sdhasidajsd
					String i = idList.get(j).getInt("id").toString();
					String key = idList.get(j).getStr("key_");
					String desc = idList.get(j).getStr("desc_");
//					String suffix = i;
//					int length = 9 - i.length();
//					for (int k = 0; k < length; k++) {
//						suffix = "0" + suffix;
//					}
					// 加密
					String exp = code.toUpperCase()+i+key;
					s1 = des.encryptStr(exp);// id+status后进行加密
					s1 = escape(s1);
					if (addNum == 0) {// 判断是否生成编号
						s1 = url + "?" + s1 + ","+(j+1) + "\r\n";
					} else {
						s1 = url + "?" + s1 + "," + code.toUpperCase()+desc +","+(j+1)+ "\r\n";
					}
					output.write(s1);
				}
				idList = null;
				output.close();
				return filePath;
			} catch (Exception e) {
				logger.error(e.getMessage());
			}
		}
		return null;
	}

	/**
	 * 获取产码数量
	 */
	@Override
	public Integer getProgress(String id) {
		if (!Common.isEmptyString(id)) {
			return null;
		}
		Integer insertCount = map.get(id);
		return insertCount;
	}

	/**
	 * 将字符串中的“+”替换为“$”
	 * 
	 * @param code
	 * @return
	 */
	private static String escape(String code) {
		StringBuilder sb = new StringBuilder();
		int len = code.trim().length();
		for (int i = 0; i < len; i++) {
			char c = code.charAt(i);
			if (c == '+') {
				sb.append("$");
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}
	

	private synchronized void put(Map<String, Integer> map, String id,
			Integer num) {
		map.put(id, num);
	}	

	/**
	 * 生成二维码图片地址
	 */
	@Override
	public String getZipImgPath(String url, Integer num,
			String filePath, String id, Integer size) {
		logger.info("method getZipImgPath url=" + url);
		logger.info("method getZipImgPath id=" + id);
		logger.info("method getZipImgPath filePath=" + filePath);
		logger.info("method getZipImgPath num=" + num);
		logger.info("method getZipImgPath size=" + size);
		// 判断传入参数是否正确
		if (!Common.isEmptyString(url)) {
			return "网络连接错误";
		}
		if (!Common.isEmptyString(id)) {
			return "网络连接错误";
		}
		if (!Common.isEmptyString(filePath)) {
			return "网络连接错误";
		}
		if (Common.isNullOrEmpty(size)) {
			return "网络连接错误";
		}
		if (Common.isNullOrEmpty(num)) {
			return "网络连接错误";
		}
		if (num > Define.ADD_QRCODE_IMG_MAX) {
			return "产码图片数量超过10W";
		}
		if (num < Define.ADD_QRCODE_MIN) {
			return "产码数量小于1";
		}

		String sourceFilePath = null;// TXT文件路径
		String tablename = "t_qcode";// 二维码表名
		String createTime = DateUtils.getStringFullDate();// 产码时间
		String idSql = "select IFNULL(max(id),0) from t_qcode";
		long maxId = 0;
		


		QrcodeConfig qc = new QrcodeConfig();
		qc.setHeight(size);
		qc.setWidth(size);

		// 生成数量大于分包数量
		if (num > Define.ADD_QRCODE_SINGLE) {
			int loop = num / Define.ADD_QRCODE_SINGLE;// 循环次数
			int surplus = num % Define.ADD_QRCODE_SINGLE;// 余数
			for (int l = 0; l < loop; l++) {// 分批处理
				maxId = Db.queryLong(idSql);
				StringBuilder sb = new StringBuilder("insert into " + tablename
						+ "  values ");
				for (int k = 0; k < Define.ADD_QRCODE_SINGLE - 1; k++) {// 拼接sql
					sb.append("(),");
				}
				sb.append("()");
				Db.update(sb.toString());
				sourceFilePath = getImgPath(qc, Define.ADD_QRCODE_SINGLE,
						filePath, maxId, tablename, createTime, url, id);
			}
			if (surplus > 0) {// 余数处理
				maxId = Db.queryLong(idSql);

				StringBuilder sb = new StringBuilder("insert into " + tablename
						+ "  values ");
				for (int k = 0; k < surplus - 1; k++) {// 拼接sql
					sb.append("(),");
				}
				sb.append("()");
				Db.update(sb.toString());

				sourceFilePath = getImgPath(qc, surplus, filePath, maxId,
						tablename, createTime, url, id);
			}

		} else {// 生成数量小于分包数量
			maxId = Db.queryLong(idSql);
			StringBuilder sb = new StringBuilder("insert into " + tablename
					+ "  values ");
			for (int k = 0; k < num - 1; k++) {// 拼接sql
				sb.append("(),");
			}
			sb.append("()");
			Db.update(sb.toString());
			sourceFilePath = getImgPath(qc, num, filePath, maxId, tablename,
					createTime, url, id);
		}

		map.remove(id);
		return getFilePath(filePath, sourceFilePath);
	}

	/**
	 * 将二维码链接转换为图片，返回文件地址
	 */
	private String getImgPath(QrcodeConfig qc, int count, String filePath,
			long maxId, String tablename, String createTime, String url,
			 String id) {
		String realPath = null;
		int insertCount = -1;
		// 加密
		DESUtil des = new DESUtil("qianlima");
		// 查询新插入二维码集合
		String sql1 = "select id from " + tablename + " where id > " + maxId;
		List<Record> idList = Db.query(sql1);
		if (idList.size() > 0) {// 集合不为空，生成txt文件

			// 文件路径为“://”+厂商名称+“//”+文件名称为产品名称_当前日期+"//"+生成数量.txt
			filePath = filePath + File.separator  + "kkbl_" + createTime
					+ File.separator;
			String s1 = new String();// 内容更新
			File f = new File(filePath);
			if (!f.exists() || !f.isDirectory()) {
				f.mkdirs();// 不存在则创建文件夹
			}
			for (int j = 0; j < count; j++) {
				// ticket的参数=产码批次(明文2位)+概率批次(明文1位)+二维码id(加密)
				// eg:1+02+sfdhasfhsdfjo, 1+12+sdhasidajsd
				String i = idList.get(j).getLong("id").toString();
				int length = 9 - i.length();
				for (int k = 0; k < length; k++) {
					i = "0" + i;
				}
				// 加密
				s1 = des.encryptStr(i);// code+id后进行加密
				s1 = escape(s1);
				s1 = url + "?" + s1;
				realPath = filePath + i + ".png";
				QrcodeFactory.createQrcodes(qc, realPath, s1, null, null);
				insertCount = j;
				put(map, id, insertCount);
			}
		}
		return realPath;
	}

	@Override
	public List<String> getPropertiesUrl() {
		List<String> urlList = new ArrayList<String>();
		String str = PropKit.use("config.properties").get("url");
		if(Common.isEmptyString(str)){//不为空，以“,”拆分
			String[] urls = str.split(",");	
			for(int i=0;i<urls.length;i++){
				if(Common.isEmptyString(urls[i])){
					urlList.add(urls[i]);					
				}
			}
		}else{
			logger.info("配置文件中url不存在");			
		}
		return urlList;
	}



}
